<template>
  <div class="chat">
    <div class="chat-content" ref="chatContent">
      <!-- 聊天记录（历史数据） -->
      <div class="chat-dialog" v-for="item in dialogDate" :key="item.id">
        <div class="chat-head">
          <img :src="item.role === 'user' ? logo : img" alt="">
        </div>
        <div class="chat-message" :style="{'background-color':item.role=='user' ? '#f6e5db' :'#ffffff'}">
          <div class="message-item" v-if="item.role === 'user'">{{ item.content }}</div>
          <div class="message-item" v-if="item.role === 'system'" v-html="renderMarkdown(item.content)"></div>
        </div>
     </div>
      <!-- 实时对话 -->
      <div
        class="chat-dialog"
        v-for="(item, index) in newMessageList"
        :key="index"
      >
        <div class="chat-head">
          <img :src="item.role === 'user' ? logo : img" alt="" />
        </div>
        <div
          class="chat-message"
          :style="{
            'background-color': item.role == 'user' ? '#f6e5db' : '#ffffff',
          }"
        >
          <div class="message-item" v-if="item.role === 'user'">{{ item.content }}</div>
          <div class="message-item" v-if="item.role === 'system'" v-html="renderMarkdown(item.content)"></div>
        </div>
      </div>
    </div>
    <div class="chat-messages">
      <el-input
        type="textarea"
        v-model="messages"
        style="flex: 1"
        @compositionstart = "handleStart"
        @compositionend = "handleEnd"
        @keyddown.enter.prevent = "handleEnter"
      ></el-input>
      <div class="messages-right">
        <button class="messages-btn" @click="senddMessage">
          <img src="@assets/dialog/sending.png" alt="" />
        </button>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { onBeforeMount, ref, nextTick, watch } from "vue";
import { useUserStore } from '@stores/useUserStore'
import { chatSave, IChatMessageItem, chatMessageList } from '@api/chat'
import img from '@assets/lll.png'
import md from '@utils/markdown'
import { useRoute } from 'vue-router'
let route = useRoute()

let messages = ref("");
const compsing = ref(false)
interface INewMessage {
  role: string,
  content: string,
  contentType: string
}
const newMessageList = ref<INewMessage[]>([])
let store = useUserStore()
const token = store.token
const { userId, logo } = store.userInfo
let id = ref(0) // 会话id
let chatContent = ref(null)
let dialogDate = ref([])

onBeforeMount( async () => {
  let res = await chatSave({
    userId,
    type: 1
  })
  console.log('会话id:', res)
  let { chatId } = res.data // 解构赋值
  id.value = chatId
})
const handleStart = () => {
  compsing.value = true
}
const handleEnd = () => {
  compsing.value = false
}
const handleEnter = () => {
  if (!compsing.value) {

  }
}
const senddMessage = () => {
  if (!compsing.value) {
    // 输入的内容不能为空；判断余额是否为0；
    // 输入内容，发送消息；
    let len = newMessageList.value.length
    newMessageList.value[len] = {
      role: 'user',
      content: messages.value,
      contentType: 'text'
    }
    // 输入框清空；
    messages.value = ''
    // 返回消息
    initEventSource()
  }
}
const initEventSource =  async () => {
  // 定义header
  let headers = { 'Content-type': 'application/json' }
  // 添加token
  if (token) {
    headers['Authorization'] = token
  }
  // 发送请求
  let res = await fetch('/api/xlx-chat/chatMessage/sendMessage', {
    headers,
    method: 'POST',
    body: JSON.stringify({
      id: id.value,
      userId: userId,
      question: newMessageList.value[newMessageList.value.length - 1].content
    })
  })
  console.log('返回的res: ', res)
  // 取流数据
  if (res.status == 200) {
    let reader = res.body?.getReader()
    let decoder = new TextDecoder('utf-8')
    let len = newMessageList.value.length
    newMessageList.value[len] = {
      role: 'system',
      content: ''
    }
    console.log('newMessageList:', newMessageList)
    while( true ) {
      const { done, value } = await reader.read()
      if (done) {
        break
      }
      const chunk = decoder.decode(value, { stream: true })
      console.log(chunk)
      try {
        const parseData = JSON.parse(chunk) // parse: 将字符串转换为 JavaScript 对象
        const content = parseData.content // 提取内容
        // replace(oldStr, newStr)函数是用来将oldStr替换成newStr的
        // 在这里的目的：确保在追加新的内容时不会重复已经存在的内容
        // 实际上这段代码会把content中与newMessageList.value[len].content相同的部分移除后再进行拼接
        content.replace(newMessageList.value[len].content, '')
        newMessageList.value[len].content += content.replace(newMessageList.value[len].content, '')
        // 滚动高度
        scrollBottom()
      } catch(err) {
        console.log(err)
      }
    }
  }
}
const renderMarkdown = (text: any) => {
  // 使用markdown转换html
  return md.render(text)
}
const scrollBottom = () => {
  nextTick(() => {
    if (chatContent.value) {
      chatContent.value.scrollTop = chatContent.value.scrollHeight
    }
  })
}
const getChatMessageList = async (id) => {
  let res = await chatMessageList({
    chatId: id
  })
  console.log('历史记录：', res)
  dialogDate.value = res.data
}
// 监听路由的变化，然后请求到对应的聊天记录
watch(route, () => {
  id.value = route.query.id
  newMessageList.value = []
  getChatMessageList(id.value)
}, { immediate: true })
</script>

<style lang="scss" scoped>
.chat {
  flex-grow: 1;
  height: 100%;
  display: flex;
  overflow: hidden;
  position: relative;
  background: #f2f2f2;
  .chat-messages {
    position: absolute;
    left: 3vw;
    right: 3vw;
    bottom: 2vw;
    box-sizing: border-box;
    background: white;
    display: flex;
    align-items: center;
    resize: none;
    height: auto;
    min-height: 24px;
    max-height: 200px;
    border-radius: 5px;
    ::v-deep .el-textarea__inner {
      box-shadow: none;
    }
    .messages-right {
      width: 50px;
      height: 100%;
      position: relative;
      .messages-btn {
        width: 50px;
        height: 50px;
        background: transparent;
        border: none;
        cursor: pointer;
        img {
          position: absolute;
          top: 50%;
          left: 50%;
          transform: translate(-50%, -50%);
          right: 10px;
          width: 1.5vw;
          height: 1.5vw;
        }
      }
    }
  }
  .chat-content {
    flex-grow: 1;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 2vw 2vw 0 2vw;
    margin-bottom: 8vw;
    box-sizing: border-box;
    padding-bottom: 2vw;
    .chat-dialog {
      margin-bottom: 1.5vw;
      display: flex;
      .chat-head {
        margin-right: 1vw;
        img {
          width: 45px;
          height: 45px;
          border-radius: 50%;
        }
      }
      .chat-message {
        flex-grow: 1;
        overflow: hidden;
        border-radius: 0.5vw;
        display: flex;
        align-items: center;
        .message-item {
          white-space: pre-wrap;
          font-size: 14px;
          color: #333;
          line-height: 25px;
          margin: 10px;
        }
      }
    }
  }
}
</style>
<style>
  .code-block {
    height: 2vw;
    font-size: 1vw;
    color: #ffffff;
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: 0.1vw solid rgba(255, 255, 255, 0.1098);
  }
  
  .copy-button {
    margin-left: 0.5vw;
    border: none;
    cursor: pointer;
  }
  
  .hljs {
    display: flex !important;
    flex-direction: column;
    border-radius: 0.5vw;
    /* background-color: #2F3052; */
    background-color: #000;
    color: #7fb421;
    font-size: 1vw;
    padding: 0 1em 1em 1em !important;
    overflow-x: auto !important;
    margin: 0.5vw 0;
    font-family: Consolas, Monaco, monospace !important;
  }
  
  .code-line {
    display: block;
    height: 2vw;
    line-height: 2vw;
    position: relative;
    padding-left: 3em;
    counter-increment: line-number;
  }
  
  .code-line::before {
    content: counter(line-number);
    position: absolute;
    left: 0;
    width: 2.5em;
    padding-right: 0.5em;
    text-align: left;
    color: #888;
  }
  
  .hljs-name {
    color: #e06c75 !important;
  }
  
  .hljs-meta,
  .hljs-meta .hljs-keyword,
  .hljs-meta .hljs-string {
    color: #be5046 !important;
  }
  
  .hljs-attr,
  .hljs-link,
  .hljs-literal,
  .hljs-number,
  .hljs-symbol,
  .hljs-variable.constant_ {
    color: #d19a66 !important;
  }
  
  .hljs-tag {
    color: #565c64 !important;
  }
  
  .hljs-addition,
  .hljs-code,
  .hljs-string,
  .hljs-title.class_.inherited__ {
    color: #98c379 !important;
  }
  </style>
